home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / NR4.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  21KB  |  770 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  * Ported to NOS by SM0RGV, 890525.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "ax25.h"
  12. #include "lapb.h"
  13. #include "netrom.h"
  14. #include "nr4.h"
  15. #include <ctype.h>
  16.  
  17. #undef NR4DEBUG
  18.  
  19. /* Globals: */
  20.  
  21. /* The circuit table */
  22.  
  23. struct nr4circp Nr4circuits[NR4MAXCIRC] ;
  24.  
  25. /* Various limits */
  26.  
  27. unsigned short Nr4window = 4 ;        /* Max window to negotiate */
  28. unsigned short Nr4retries = 10 ;    /* Max retries */
  29. unsigned short Nr4qlimit = 2048 ;    /* Max bytes on receive queue */
  30.  
  31. /* Timers */
  32.  
  33. long Nr4irtt = 15000 ;            /* Initial round trip time */
  34. long Nr4acktime = 3000 ;        /* ACK delay timer */
  35. long Nr4choketime = 180000 ;    /* CHOKEd state timeout */
  36.  
  37. static void nr4ackours __ARGS((struct nr4cb *, unsigned, int));
  38. static void nr4choke __ARGS((struct nr4cb *));
  39. static void nr4gotnak __ARGS((struct nr4cb *, unsigned));
  40. static void nr4rframe __ARGS((struct nr4cb *, unsigned, struct mbuf *));
  41.  
  42. /* This function is called when a net/rom layer four frame */
  43. /* is discovered inside a datagram addressed to us */
  44.  
  45. void
  46. nr4input(hdr,bp)
  47. struct nr4hdr *hdr ;
  48. struct mbuf *bp ;
  49. {
  50.     struct nr4hdr rhdr ;
  51.     struct nr4cb *cb, *cb2 ;
  52.     struct ax25_addr dest ;
  53.     int op ;
  54.     unsigned window ;
  55.     int acceptc ;        /* indicates that connection should be accepted */
  56.     int newconn ;        /* indicates that this is a new incoming */
  57.                         /* connection.  You'll see. */
  58.     int gotchoke ;        /* The choke flag was set in this packet */        
  59.     int i ;
  60.     
  61.     op = hdr->opcode & NR4OPCODE ;    /* Mask off flags */
  62.     
  63.     if (op == NR4OPCONRQ) {            /* process connect request first */
  64.         acceptc = 1 ;
  65.         newconn = 0 ;
  66.  
  67.         /* These fields are sent regardless of success */
  68.         
  69.         rhdr.yourindex = hdr->u.conreq.myindex ;
  70.         rhdr.yourid = hdr->u.conreq.myid ;
  71.         dest = hdr->u.conreq.node ;
  72.  
  73.         /* Check to see if we have already received a connect */
  74.         /* request for this circuit. */
  75.  
  76.         if ((cb = match_n4circ(hdr->u.conreq.myindex, hdr->u.conreq.myid,
  77.                                   &hdr->u.conreq.user, &hdr->u.conreq.node))
  78.              == NULLNR4CB) {    /* No existing circuit if NULL */
  79.  
  80.             /* Try to get a new circuit */
  81.  
  82.             if ((cb = new_n4circ()) == NULLNR4CB)
  83.                 acceptc = 0 ;
  84.             /* See if we have any listening sockets */
  85.             for (i = 0 ; i < NR4MAXCIRC ; i++) {
  86.                 if ((cb2 = Nr4circuits[i].ccb) == NULLNR4CB)
  87.                 continue ;/* not an open circuit */
  88.                 if (cb2->state == NR4STLISTEN)
  89.                     /* A listener was found */
  90.                     break;
  91.             }
  92.             if (i == NR4MAXCIRC) { /* We are refusing connects */
  93.                 acceptc = 0;
  94.                 free_n4circ(cb);
  95.             }
  96.             if (acceptc) {
  97.                 /* Load the listeners settings */
  98.                 cb->clone = cb2->clone;
  99.                 cb->user = cb2->user;
  100.                 cb->t_upcall = cb2->t_upcall;
  101.                 cb->s_upcall = cb2->s_upcall;
  102.                 cb->r_upcall = cb2->r_upcall;
  103.                 ASSIGN(cb->local,cb2->local);
  104.  
  105.         /* Window is set to min of the offered and local windows */
  106.                 
  107.                 window = hdr->u.conreq.window > Nr4window ?
  108.                          Nr4window : hdr->u.conreq.window ;
  109.  
  110.                 if (init_nr4window(cb, window) == -1) {
  111.                     free_n4circ(cb) ;
  112.                     acceptc = 0 ;
  113.                 } else {
  114.                     /* Set up control block */
  115.                     cb->yournum = hdr->u.conreq.myindex ;
  116.                     cb->yourid = hdr->u.conreq.myid ;
  117.                     memcpy(cb->remote.user_call,
  118.                            &hdr->u.conreq.user,AXALEN) ;
  119.                     memcpy(cb->remote.node_call,
  120.                            &hdr->u.conreq.node,AXALEN) ;
  121.                     /* Default round trip time */
  122.                     cb->srtt = Nr4irtt ;
  123.                     /* set up timers, window pointers */
  124.                     nr4defaults(cb) ;
  125.                     cb->state = NR4STDISC ;
  126.                     newconn = 1 ;
  127.                 } /* End if window successfully allocated */
  128.                 
  129.             }    /* End if new circuit available */
  130.             
  131.          } /* End if no existing circuit matching parameters */
  132.  
  133.         /* Now set up response */
  134.  
  135.         if (!acceptc) {
  136.             rhdr.opcode = NR4OPCONAK | NR4CHOKE ;/* choke means reject */
  137.             rhdr.u.conack.myindex = 0 ;
  138.             rhdr.u.conack.myid = 0 ;
  139.             rhdr.u.conack.window = 0 ;
  140.         } else {
  141.             rhdr.opcode = NR4OPCONAK ;
  142.             rhdr.u.conack.myindex = cb->mynum ;
  143.             rhdr.u.conack.myid = cb->myid ;
  144.             rhdr.u.conack.window = cb->window ;
  145.         }
  146.         nr4sframe(&dest, &rhdr, NULLBUF) ;
  147.  
  148.         /* Why, you ask, do we wait until now for the state change */
  149.         /* upcall?  Well, it's like this:  if the state change triggers */
  150.         /* something like the mailbox to send its banner, the banner */
  151.         /* would have gone out *before* the conn ack if we'd done this */
  152.         /* in the code above.  This is what happens when you don't plan */
  153.         /* too well.  Learn from my mistakes :-) */
  154.         
  155.         if (newconn)
  156.             nr4state(cb, NR4STCON) ;/* connected (no 3-way handshake) */
  157.             
  158.         free_p(bp) ;
  159.         return ;
  160.     } /* end connect request code */
  161.  
  162.     /* validate circuit number */
  163.  
  164.     if ((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB) {
  165.         free_p(bp) ;
  166.         return ;
  167.     }
  168.  
  169.     /* Check for choke flag */
  170.  
  171.     if (hdr->opcode & NR4CHOKE)
  172.         gotchoke = 1 ;
  173.     else
  174.         gotchoke = 0 ;
  175.     
  176.     /* Here's where the interesting stuff gets done */
  177.  
  178.     switch (cb->state) {
  179.       case NR4STCPEND:
  180.         switch (op) {
  181.           case NR4OPCONAK:
  182.             stop_timer(&cb->tcd) ;
  183.             if (gotchoke) {                    /* connect rejected */
  184.                 cb->dreason = NR4RREFUSED ;
  185.                 nr4state(cb, NR4STDISC) ;
  186.                 break ;
  187.             }
  188.             cb->yournum = hdr->u.conack.myindex ;
  189.             cb->yourid = hdr->u.conack.myid ;
  190.             window = hdr->u.conack.window > Nr4window ?
  191.                      Nr4window : hdr->u.conack.window ;
  192.  
  193.             if (init_nr4window(cb, window) == -1) {
  194.                 cb->dreason = NR4RRESET ;
  195.                 nr4state(cb, NR4STDISC) ;
  196.             } else {
  197.                 nr4defaults(cb) ;    /* set up timers, window pointers */
  198.                 
  199.                 if (cb->cdtries == 1)             /* No retries */
  200.                     cb->srtt = cb->tcd.count * MSPTICK ;/* Use measured rtt */
  201.                 else
  202.                     cb->srtt = Nr4irtt ;        /* else use default */
  203.                     
  204.                 nr4state(cb, NR4STCON) ;
  205.                 nr4output(cb) ;        /* start sending anything on the txq */
  206.             }
  207.             break ;
  208.  
  209.           default:        /* We can't respond to anything else without */
  210.                           /* Their ID and index */
  211.               free_p(bp) ;
  212.             return ;
  213.         }
  214.         break ;
  215.         
  216.       case NR4STCON:
  217.         switch (op) {
  218.           case NR4OPDISRQ:
  219.             /* format reply packet */
  220.             rhdr.opcode = NR4OPDISAK ;
  221.             rhdr.yourindex = cb->yournum ;
  222.             rhdr.yourid = cb->yourid ;
  223.     
  224.             nr4sframe((struct ax25_addr *)cb->remote.node_call,
  225.                   &rhdr, NULLBUF) ;
  226.  
  227.             cb->dreason = NR4RREMOTE ;
  228.             nr4state(cb, NR4STDISC) ;
  229.  
  230.             break ;
  231.             
  232.           case NR4OPINFO:
  233.             /* Do receive frame processing */
  234.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  235.  
  236.             /* Reset the choke flag if no longer choked.  Processing */
  237.             /* the ACK will kick things off again. */
  238.             
  239.             if (cb->choked && !gotchoke) {
  240.                 stop_timer(&cb->tchoke) ;
  241.                 cb->choked = 0 ;
  242.             }
  243.                 
  244.             /* We delay processing the receive sequence number until */
  245.             /* now, because the ACK might pull more off the txq and send */
  246.             /* it, and we want the implied ACK in those frames to be right */
  247.  
  248.             /* Only process NAKs if the choke flag is off.  It appears */
  249.             /* that NAKs should never be sent with choke on, by the way, */
  250.             /* but you never know, considering that there is no official */
  251.             /* standard for this protocol */
  252.             
  253.             if (hdr->opcode & NR4NAK && !gotchoke)
  254.                 nr4gotnak(cb, hdr->u.info.rxseq) ;
  255.  
  256.             /* We always do ACK processing, too, since the NAK of one */
  257.             /* packet may be the implied ACK of another.  The gotchoke */
  258.             /* flag is used to prevent sending any new frames, since */
  259.             /* we are just going to purge them next anyway if this is */
  260.             /* the first time we've seen the choke flag.  If we are */
  261.             /* already choked, this call will return immediately. */
  262.             
  263.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke) ;
  264.  
  265.             /* If we haven't seen the choke flag before, purge the */
  266.             /* send window and set the timer and the flag. */
  267.             
  268.             if (!cb->choked && gotchoke)
  269.                 nr4choke(cb) ;
  270.             
  271.             break ;
  272.  
  273.           case NR4OPACK:
  274.             if (cb->choked && !gotchoke) {    /* clear choke if appropriate */
  275.                 stop_timer(&cb->tchoke) ;
  276.                 cb->choked = 0 ;
  277.             }
  278.                 
  279.               if (hdr->opcode & NR4NAK && !gotchoke)
  280.                 nr4gotnak(cb, hdr->u.ack.rxseq) ;    /* process NAKs */
  281.                 
  282.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke) ; /* and ACKs */
  283.  
  284.             if (!cb->choked && gotchoke)    /* First choke seen */
  285.                 nr4choke(cb) ;                /* Set choke status */
  286.  
  287.             break ;
  288.         }
  289.         break ;
  290.         
  291.       case NR4STDPEND:
  292.         switch (op) {
  293.           case NR4OPDISAK:
  294.               cb->dreason = NR4RNORMAL ;
  295.             nr4state(cb, NR4STDISC) ;
  296.             break ;
  297.             
  298.           case NR4OPINFO:
  299.             /* We can still do receive frame processing until */
  300.             /* the disconnect acknowledge arrives, but we won't */
  301.             /* bother to process ACKs, since we've flushed our */
  302.             /* transmit buffers and queue already. */
  303.             
  304.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  305.  
  306.             break ;
  307.         }
  308.     
  309.     }    /* End switch(state) */
  310.  
  311. }
  312.  
  313.  
  314. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  315.  * type is info.
  316.  */
  317.  
  318. void
  319. nr4sframe(dest, hdr, bp)
  320. struct ax25_addr *dest ;
  321. struct nr4hdr *hdr ;
  322. struct mbuf *bp ;
  323. {
  324.     struct mbuf *n4b ;
  325.  
  326.     if ((n4b = htonnr4(hdr)) == NULLBUF) {
  327.         free_p(bp) ;
  328.         return ;
  329.     } else {
  330.         append(&n4b, bp) ;
  331.         nr3output(dest, n4b) ;
  332.     }
  333. }
  334.  
  335. /* Receive frame processing */
  336.  
  337. static void
  338. nr4rframe(cb, rxseq, bp)
  339. struct nr4cb *cb ;
  340. unsigned rxseq ;
  341. struct mbuf *bp ;
  342. {
  343.     struct nr4hdr rhdr ;
  344.     unsigned window = cb->window ;
  345.     unsigned rxbuf = rxseq % window ;
  346.     unsigned newdata = 0 ;        /* whether to upcall */
  347.  
  348. #ifdef NR4DEBUG
  349.     printf("Processing received info\n") ;
  350. #endif
  351.  
  352.     /* If we're choked, just reset the ACK timer to blast out */
  353.     /* another CHOKE indication after the ackdelay */
  354.  
  355.     if (cb->qfull) {
  356.         start_timer(&cb->tack) ;
  357.         return ;
  358.     }
  359.     
  360.     /* If the frame is out of sequence, NAK it if we haven't */
  361.     /* already done so */
  362.     
  363.       if (rxseq != cb->rxpected && !cb->naksent) {
  364. #ifdef NR4DEBUG
  365.         printf("Frame out of sequence -- expected %u, got %u.\n",
  366.                cb->rxpected, rxseq) ;
  367. #endif                
  368.         rhdr.opcode = NR4OPACK | NR4NAK ;
  369.         rhdr.yourindex = cb->yournum ;
  370.         rhdr.yourid = cb->yourid ;
  371.         rhdr.u.ack.rxseq = cb->rxpected ;
  372.         nr4sframe((struct ax25_addr *)cb->remote.node_call,
  373.               &rhdr, NULLBUF) ;
  374.         
  375.         /* Now make sure we don't send any more of these until */
  376.         /* we see some good data.  Otherwise full window retransmissions */
  377.         /* would result in a flurry of NAKs */
  378.         
  379.         cb->naksent = 1 ;
  380.     }
  381.             
  382.     /* If this is a new frame, within the window, buffer it, */
  383.     /* then see what we can deliver */
  384.             
  385.     if (nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  386.         && !cb->rxbufs[rxbuf].occupied) {
  387. #ifdef NR4DEBUG
  388.         printf("Frame within window\n") ;
  389. #endif
  390.         cb->rxbufs[rxbuf].occupied = 1 ;
  391.         cb->rxbufs[rxbuf].data = bp ;
  392.                 
  393.         for (rxbuf = cb->rxpected % window ; cb->rxbufs[rxbuf].occupied ; 
  394.              rxbuf = cb->rxpected % window) {
  395. #ifdef NR4DEBUG
  396.             printf("Removing frame from buffer %d\n", rxbuf) ;
  397. #endif
  398.             newdata = 1 ;
  399.             cb->rxbufs[rxbuf].occupied = 0 ;
  400.             append(&cb->rxq,cb->rxbufs[rxbuf].data) ;
  401.             cb->rxbufs[rxbuf].data = NULLBUF ;
  402.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK ;
  403.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK ;
  404.         }
  405.         if (newdata) {
  406.             cb->naksent = 0 ;    /* OK to send NAKs again */
  407.             if (cb->r_upcall != NULLVFP)
  408.                 (*cb->r_upcall)(cb,len_mbuf(cb->rxq)) ;
  409.  
  410.             /* Now that our upcall has had a shot at the queue, */
  411.             /* see if it's past the queue length limit.  If so, */
  412.             /* go into choked mode (i.e. flow controlled). */
  413.  
  414.             if (len_mbuf(cb->rxq) > Nr4qlimit) {
  415.                 cb->qfull = 1 ;
  416.                 nr4ackit((char *)cb) ;    /* Tell `em right away */
  417.             } else
  418.                 start_timer(&cb->tack) ;
  419.         }
  420.     } else     /* It's out of the window or we've seen it already */
  421.         free_p(bp) ;
  422. }
  423.  
  424.  
  425. /* Send the transmit buffer whose sequence number is seq */
  426.  
  427. void
  428. nr4sbuf(cb, seq)
  429. struct nr4cb *cb ;
  430. unsigned seq ;
  431. {
  432.     struct nr4hdr hdr ;
  433.     struct mbuf *bufbp, *bp ;
  434.     unsigned bufnum = seq % cb->window ;
  435.     struct timer *t ;
  436.     
  437.     /* sanity check */
  438.  
  439.     if (bufnum >= cb->window) {
  440. #ifdef NRDEBUG
  441.         printf("sbuf: buffer number %u beyond window\n",bufnum) ;
  442. #endif
  443.         return ;
  444.     }
  445.  
  446.     /* Stop the ACK timer, since our sending of the frame is */
  447.     /* an implied ACK. */
  448.  
  449.     stop_timer(&cb->tack) ;
  450.     
  451.     /* Duplicate the mbuf, since we have to keep it around */
  452.     /* until it is acknowledged */
  453.     
  454.     bufbp = cb->txbufs[bufnum].data ;
  455.  
  456.     /* Notice that we use copy_p instead of dup_p.  This is because */
  457.     /* a frame can still be sitting on the AX.25 send queue when it */
  458.     /* get acknowledged, and we don't want to deallocate its data */
  459.     /* before it gets sent! */
  460.     
  461.     if ((bp = copy_p(bufbp, len_mbuf(bufbp))) == NULLBUF) {
  462.         free_mbuf(bp) ;
  463.         return ;
  464.     }
  465.  
  466.     /* Prepare the header */
  467.     if (cb->qfull)                /* are we choked? */
  468.         hdr.opcode = NR4OPINFO | NR4CHOKE ;
  469.     else
  470.         hdr.opcode = NR4OPINFO ;
  471.     hdr.yourindex = cb->yournum ;
  472.     hdr.yourid = cb->yourid ;
  473.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK) ;
  474.     hdr.u.info.rxseq = cb->rxpected ;
  475.     
  476.     /* Send the frame, then set and start the timer */
  477.  
  478.     nr4sframe((struct ax25_addr *)cb->remote.node_call, &hdr, bp) ;
  479.  
  480.     t = &cb->txbufs[bufnum].tretry ;
  481.     t->start = (1 << cb->blevel) *
  482.                (2 * cb->mdev + cb->srtt + MSPTICK) / MSPTICK ;
  483.     start_timer(t) ;
  484.  
  485.     return ;
  486. }
  487.  
  488. /* Check to see if any of our frames have been ACKed */
  489.  
  490. static void
  491. nr4ackours(cb, seq, gotchoke)
  492. struct nr4cb *cb ;
  493. unsigned seq ;
  494. int gotchoke ;    /* The choke flag is set in the received frame */
  495. {
  496.     unsigned txbuf ;
  497.     struct timer *t ;
  498.     
  499.     /* If we are choked, there is nothing in the send window */
  500.     /* by definition, so we can just return. */
  501.     
  502.     if (cb->choked)
  503.         return ;
  504.         
  505.     /* Adjust seq to point to the frame being ACK'd, not the one */
  506.     /* beyond it, which is how it arrives. */
  507.  
  508.     seq = (seq - 1) & NR4SEQMASK ;
  509.  
  510.     /* Free up all the ack'd frames, and adjust the round trip */
  511.     /* timing stuff */
  512.     
  513.     while (nr4between(cb->ackxpected, seq, cb->nextosend)) {
  514. #ifdef NR4DEBUG
  515.         printf("Sequence # %u acknowledged\n", seq) ;
  516. #endif
  517.         cb->nbuffered-- ;
  518.         txbuf = cb->ackxpected % cb->window ;
  519.         stop_timer(&cb->txbufs[txbuf].tretry) ;
  520.         free_mbuf(cb->txbufs[txbuf].data) ;
  521.         cb->txbufs[txbuf].data = NULLBUF ;
  522.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK ;
  523.  
  524.         /* Round trip time estimation, cribbed from TCP */
  525.  
  526.         if (cb->txbufs[txbuf].retries == 0) {    /* We only sent this one once */
  527.             int32 rtt ;
  528.             int32 abserr ;
  529.  
  530.             t = &cb->txbufs[txbuf].tretry ;
  531.             rtt = (t->start - t->count) * MSPTICK ;    /* get our rtt in msec */
  532.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt ;
  533.             cb->srtt = (cb->srtt * 7 + rtt) >> 3 ;
  534.             cb->mdev = (cb->mdev * 3 + abserr) >> 2 ;
  535.  
  536.             /* Reset the backoff level */
  537.  
  538.             cb->blevel = 0 ;
  539.         } 
  540.     }
  541.  
  542.     /* Now we recalculate tmax, the maximum number of retries for */
  543.     /* any frame in the window.  tmax is used as a baseline to */
  544.     /* determine when the window has reached a new high in retries. */
  545.     /* We don't want to increment blevel for every frame that times */
  546.     /* out, since that would lead to us backing off too fast when */
  547.     /* all the frame timers expired at around the same time. */
  548.  
  549.     cb->txmax = 0 ;
  550.     
  551.     for (seq = cb->ackxpected ;
  552.          nr4between(cb->ackxpected, seq, cb->nextosend) ;
  553.          seq = (seq + 1) & NR4SEQMASK)
  554.         if (cb->txbufs[seq % cb->window].retries > cb->txmax)
  555.             cb->txmax = cb->txbufs[seq % cb->window].retries ;
  556.  
  557.     /* This is kind of a hack.  This function is called under */
  558.     /* three different conditions:  either we are choked, in */
  559.     /* which case we return immediately, or we are not choked, */
  560.     /* in which case we proceed normally to keep the send */
  561.     /* window full, or we have seen the choke flag for the first */
  562.     /* time.  In the last case, gotchoke is true while cb->choked */
  563.     /* is false.  We want to process any acknowledgments of existing */
  564.     /* frames in the send window before we purge it, while at the */
  565.     /* same time we don't want to take anything else off the txq */
  566.     /* or send it out.  So, in the third case we listed, we return */
  567.     /* now since we've processed the ACK. */
  568.     
  569.     if (gotchoke)
  570.         return ;
  571.         
  572.     nr4output(cb) ;            /* yank stuff off txq and send it */
  573.  
  574.     /* At this point, either the send window is full, or */
  575.     /* nr4output() didn't find enough on the txq to fill it. */
  576.     /* If the window is not full, then the txq must be empty, */
  577.     /* and we'll make a tx upcall */
  578.     
  579.     if (cb->nbuffered < cb->window)    
  580.         if (cb->t_upcall != NULLVFP)
  581.             (*cb->t_upcall)(cb, (cb->window - cb->nbuffered) * NR4MAXINFO) ;
  582.  
  583. }
  584.  
  585.  
  586. /* If the send window is open and there are frames on the txq,
  587.  * move as many as possible to the transmit buffers and send them.
  588.  * Return the number of frames sent.
  589.  */
  590.  
  591. int
  592. nr4output(cb)
  593. struct nr4cb *cb ;
  594. {
  595.     int numq, i ;
  596.     struct mbuf *bp ;
  597.     struct nr4txbuf *tp ;
  598.  
  599.     /* Are we in the proper state? */
  600.  
  601.     if (cb->state != NR4STCON || cb->choked)
  602.         return 0 ;                /* No sending if not connected */
  603.                                 /* or if choked */
  604.         
  605.     /* See if the window is open */
  606.     
  607.     if (cb->nbuffered >= cb->window)
  608.         return 0 ;
  609.  
  610.     numq = len_q(cb->txq) ;
  611.     
  612. #ifdef NR4DEBUG
  613.     printf("nr4output: %d packets on txq\n", numq) ;
  614. #endif
  615.     
  616.     for (i = 0 ; i < numq ; i++) {
  617.  
  618.         bp = dequeue(&cb->txq) ;
  619.  
  620. #ifdef NR4DEBUG
  621.         if (len_mbuf(bp) > NR4MAXINFO) {    /* should be checked higher up */
  622.             printf("Upper layers queued too big a buffer\n") ;
  623.             continue ;
  624.         }
  625. #endif
  626.         /* Set up and send buffer */
  627.         
  628.         tp = &cb->txbufs[cb->nextosend % cb->window] ;
  629.         tp->retries = 0 ;
  630.         tp->data = bp ;
  631.         nr4sbuf(cb, cb->nextosend) ;
  632.  
  633.         /* Update window and buffered count */
  634.  
  635.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK ;
  636.         if (++cb->nbuffered >= cb->window)
  637.             break ;
  638.     }
  639.     return i ;        
  640. }
  641.  
  642. void
  643. nr4state(cb, newstate)
  644. struct nr4cb *cb ;
  645. int newstate ;
  646. {
  647.     int i ;
  648.     int oldstate = cb->state ;
  649.     
  650.     cb->state = newstate ;
  651.  
  652.     switch (cb->state) {
  653.       case NR4STDPEND:
  654.           stop_timer(&cb->tchoke);
  655.  
  656.         /* When we request a disconnect, we lose the contents of */
  657.         /* our transmit queue and buffers, but we retain our ability */
  658.         /* to receive any packets in transit until a disconnect */
  659.         /* acknowledge arrives */
  660.         
  661.         free_q(&cb->txq) ;
  662.         
  663.         for (i = 0 ; i < cb->window ; i++) {
  664.             free_mbuf(cb->txbufs[i].data) ;
  665.             cb->txbufs[i].data = NULLBUF ;
  666.             stop_timer(&cb->txbufs[i].tretry) ;
  667.         }
  668.         
  669.         /* Tidy up stats: roll the top window pointer back */
  670.         /* and reset nbuffered to reflect this.  Not really */
  671.         /* necessary, but leads to a bit more truth telling */
  672.         /* in the status displays. */
  673.  
  674.         cb->nextosend = cb->ackxpected ;
  675.         cb->nbuffered = 0 ;
  676.  
  677.         break ;
  678.         
  679.       case NR4STDISC:
  680.         stop_timer(&cb->tchoke) ;
  681.         stop_timer(&cb->tack) ;
  682.         stop_timer(&cb->tcd) ;
  683.  
  684.         /* We don't clear the rxq, since the state change upcall */
  685.         /* may pull something off of it at the last minute. */
  686.         
  687.         free_q(&cb->txq) ;
  688.  
  689.         /* The following loop will only be executed if the */
  690.         /* window was set, since when the control block is */
  691.         /* calloc'd the window field gets a 0 in it.  This */
  692.         /* protects us from dereferencing an unallocated */
  693.         /* window buffer pointer */
  694.         
  695.         for (i = 0 ; i < cb->window ; i++) {
  696.             free_mbuf(cb->rxbufs[i].data) ;
  697.             cb->rxbufs[i].data = NULLBUF ;
  698.             free_mbuf(cb->txbufs[i].data) ;
  699.             cb->txbufs[i].data = NULLBUF ;
  700.             stop_timer(&cb->txbufs[i].tretry) ;
  701.         }
  702.             
  703.         break ;
  704.     }
  705.  
  706.     if (oldstate != newstate && cb->s_upcall != NULLVFP)
  707.         (*cb->s_upcall)(cb, oldstate, newstate) ;
  708.  
  709.     /* We take responsibility for deleting the circuit */
  710.     /* descriptor.  Don't do this anywhere else! */
  711.     
  712.     if (newstate == NR4STDISC)
  713.         free_n4circ(cb) ;
  714.     
  715. }
  716.  
  717. /* Process NAKs.  seq indicates the next frame expected by the
  718.  * NAK'ing station.
  719.  */
  720.  
  721. static void
  722. nr4gotnak(cb, seq)
  723. struct nr4cb *cb ;
  724. unsigned seq ;
  725. {
  726.     if (nr4between(cb->ackxpected, seq, cb->nextosend))
  727.         nr4sbuf(cb, seq) ;
  728. }
  729.  
  730.  
  731. /* This is called when we first get a CHOKE indication from the
  732.  * remote.  It purges the send window and sets the choke timer.
  733.  */
  734.  
  735. static void
  736. nr4choke(cb)
  737. struct nr4cb *cb ;
  738. {
  739.     unsigned seq ;
  740.     struct mbuf *q, *bp ;
  741.     struct nr4txbuf *t ;
  742.  
  743.     q = cb->txq ;
  744.  
  745.     /* We purge the send window, returning the buffers to the */
  746.     /* txq in the proper order. */
  747.  
  748.     for (seq = (cb->nextosend - 1) & NR4SEQMASK ;
  749.          nr4between(cb->ackxpected, seq, cb->nextosend) ;
  750.          seq = (seq - 1) & NR4SEQMASK) {
  751.  
  752.         t = &cb->txbufs[seq % cb->window] ;
  753.         stop_timer(&t->tretry) ;
  754.         bp = t->data ;
  755.         t->data = NULLBUF ;
  756.         enqueue(&bp, q) ;    /* prepend this packet to the queue */
  757.         q = bp ;
  758.      }
  759.  
  760.     cb->nextosend = cb->ackxpected ;    /* close the window */
  761.     cb->nbuffered = 0 ;                    /* nothing in the window */
  762.     cb->txq = q ;            /* Replace the txq with the one that has */
  763.                             /* the purged packets prepended */
  764.     cb->choked = 1 ;        /* Set the choked flag */
  765.  
  766.     start_timer(&cb->tchoke) ;
  767.     
  768. }
  769.  
  770.